package com.appengine.paranoid_android.lost;

import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
import android.preference.PreferenceManager;
import android.preference.Preference.OnPreferenceClickListener;
import android.provider.Contacts;
import android.provider.Contacts.ContactMethods;
import android.provider.Contacts.People;
import android.provider.Contacts.Phones;
import android.util.Log;

public class InfoSetup extends PreferenceActivity {
  private static final boolean DEBUG = false;
  private static final String TAG = "Info.Setup";

  private static final int REQUEST_CODE_PICK_CONTACT = 0;
  private static final String CONTACT_KEY = "contact";
  private static final String PHONE_KEY_PREFIX = "phone_";
  private static final String CONTACT_METHOD_KEY_PREFIX = "contact_method_";

  static final String MESSAGE_PREFERENCE = "message";
  private static final String DISPLAY_GROUP_PREFERENCE = "display_group";

  private Preference mContact;
  private PreferenceCategory mDisplayGroup;
  private SharedPreferences mPreferences;
  // Disable spurious message updates while (re)building the preference screen.
  private boolean mDisableMessageUpdates;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    addPreferencesFromResource(R.xml.setup);
    mContact = findPreference(CONTACT_KEY);
    mContact.setOnPreferenceClickListener(new OnPreferenceClickListener() {
      @Override
      public boolean onPreferenceClick(Preference preference) {
        Intent i = new Intent(android.content.Intent.ACTION_PICK, People.CONTENT_URI);
        startActivityForResult(i, REQUEST_CODE_PICK_CONTACT);
        return true;
      }
    });
    mDisplayGroup = (PreferenceCategory) findPreference(DISPLAY_GROUP_PREFERENCE);

    mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
    mPreferences.registerOnSharedPreferenceChangeListener(new SharedPreferences.OnSharedPreferenceChangeListener() {
      @Override
      public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
        if (DEBUG) Log.d(TAG, "Preference changed: " + key);
        // When a phone or contact method is checked/unchecked update the info message accordingly.
        if (key.startsWith(PHONE_KEY_PREFIX) || key.startsWith(CONTACT_METHOD_KEY_PREFIX)) {
          updateInfoMessage();
        }
      }
    });

    String contact = mPreferences.getString(CONTACT_KEY, null);
    if (contact != null) {
      if (DEBUG) Log.d(TAG, "Loaded contact " + contact);
      displayContact(Uri.parse(contact), false);
    }

    Context context = getApplicationContext();
    Intent service = new Intent(context, InfoService.class);
    context.startService(service);
  }

  @Override
  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode != RESULT_CANCELED) {
      switch (requestCode) {
        case REQUEST_CODE_PICK_CONTACT:
          if (data == null) {
            if (DEBUG) Log.e(TAG, "No intent data returned.");
            return;
          }

          final Uri personUri = data.getData();
          if (personUri == null) {
            if (DEBUG) Log.e(TAG, "Intent data contained no person URI.");
            return;
          }

          displayContact(personUri, true);
          return;

        default:
          if (DEBUG) Log.w(TAG, "Unknown activity result: " + requestCode + ", " + resultCode + ", " + data);
          break;
      }
    }

    super.onActivityResult(requestCode, resultCode, data);
  }

  private void displayContact(Uri personUri, boolean contactChanged) {
    if (DEBUG) Log.v(TAG, "Displaying " + personUri.toString() + ", contactChanged " + contactChanged);

    Cursor c = getContentResolver().query(personUri, null, null, null, null);
    if (c == null || !c.moveToNext()) {
      if (DEBUG) Log.e(TAG, "No such contact: " + personUri);
      c.close();
      return;
    }
    mContact.setTitle(c.getString(c.getColumnIndexOrThrow(People.DISPLAY_NAME)));
    int personId = c.getInt(c.getColumnIndexOrThrow(People._ID));
    c.close();

    mDisableMessageUpdates = true;
    mDisplayGroup.removeAll();
    boolean hasContactInformation = false;

    // Phone numbers.
    final Uri phonesUri = Uri.withAppendedPath(personUri, People.Phones.CONTENT_DIRECTORY);
    c = getContentResolver().query(phonesUri, null, null, null, People.Phones.ISPRIMARY + " desc");
    if (c == null) {
      if (DEBUG) Log.e(TAG, "Phones query returned null cursor.");
      return;
    }
    final String contactMethodPhone = getResources().getString(R.string.contact_method_phone);
    while (c.moveToNext()) {
      int phoneId = c.getInt(c.getColumnIndexOrThrow(People.Phones._ID));
      String number = c.getString(c.getColumnIndexOrThrow(People.Phones.NUMBER));
      int type = c.getInt(c.getColumnIndexOrThrow(People.Phones.TYPE));
      String label = c.getString(c.getColumnIndexOrThrow(People.Phones.LABEL));
      label = Phones.getDisplayLabel(this, type, label).toString();

      CheckBoxPreference pref = new CheckBoxPreference(this);
      pref.setTitle(number);
      pref.setSummary(String.format(contactMethodPhone, label));
      pref.setKey(PHONE_KEY_PREFIX + personId + "_" + phoneId);
      mDisplayGroup.addPreference(pref);
      // Only set checked state after adding to screen, otherwise state doesn't get saved.
      if (contactChanged) {
        pref.setChecked(c.getInt(c.getColumnIndexOrThrow(People.Phones.ISPRIMARY)) != 0);
      }
      hasContactInformation = true;
    }
    c.close();

    // Other contact methods.
    final Uri contactMethodsUri = Uri.withAppendedPath(personUri, People.ContactMethods.CONTENT_DIRECTORY);
    c = getContentResolver().query(contactMethodsUri, null, null, null, People.ContactMethods.ISPRIMARY + " desc");
    if (c == null) {
      if (DEBUG) Log.e(TAG, "ContactMethods query returned null cursor.");
      return;
    }

    final String contactMethodIm = getResources().getString(R.string.contact_method_im);
    final String contactMethodEmail = getResources().getString(R.string.contact_method_email);
    final String contactMethodPostal = getResources().getString(R.string.contact_method_postal);
    final String[] protocolStrings = getResources().getStringArray(android.R.array.imProtocols);
    String label, format;
    while (c.moveToNext()) {
      final int contactMethodId = c.getInt(c.getColumnIndexOrThrow(People.ContactMethods._ID));
      int kind = c.getInt(c.getColumnIndexOrThrow(People.ContactMethods.KIND));
      String data = c.getString(c.getColumnIndexOrThrow(People.ContactMethods.DATA));
      if (kind == Contacts.KIND_IM) {
        Object protocolObj = ContactMethods.decodeImProtocol(
            c.getString(c.getColumnIndexOrThrow(People.ContactMethods.AUX_DATA)));
        if (protocolObj instanceof Number) {
          int protocol = ((Number) protocolObj).intValue();
          label = protocolStrings[protocol];
        } else {
          label = (String) protocolObj;
        }
        format = contactMethodIm;
      } else {
        label = c.getString(c.getColumnIndexOrThrow(People.ContactMethods.LABEL));
        int type = c.getInt(c.getColumnIndexOrThrow(People.ContactMethods.TYPE));
        label = ContactMethods.getDisplayLabel(this, kind, type, label).toString();
        switch (kind) {
          case Contacts.KIND_PHONE:
            format = contactMethodPhone;
            break;
          case Contacts.KIND_EMAIL:
            format = contactMethodEmail;
            break;
          case Contacts.KIND_POSTAL:
            format = contactMethodPostal;
            break;
          default:
            format = "%s";
            break;
        }
      }

      CheckBoxPreference pref = new CheckBoxPreference(this);
      pref.setTitle(data);
      pref.setSummary(String.format(format, label));
      pref.setKey(CONTACT_METHOD_KEY_PREFIX + personId + "_" + contactMethodId);
      mDisplayGroup.addPreference(pref);
      // Only set checked state after adding to screen, otherwise state doesn't get saved.
      if (contactChanged) {
        pref.setChecked(c.getInt(c.getColumnIndexOrThrow(People.ContactMethods.ISPRIMARY)) != 0);
      }
      hasContactInformation = true;
    }
    c.close();

    if (!hasContactInformation) {
      Preference pref = new Preference(this);
      //pref.setEnabled(false);
      pref.setLayoutResource(R.layout.no_contact_method);
      mDisplayGroup.addPreference(pref);
    }

    if (contactChanged) {
      SharedPreferences.Editor edit = mPreferences.edit();
      edit.putString(CONTACT_KEY, personUri.toString());
      edit.putString(MESSAGE_PREFERENCE, getInfoMessage());
      edit.commit();
    }

    // Done rebuilding the screen, enable message updates on preference changes.
    mDisableMessageUpdates = false;
  }

  private void updateInfoMessage() {
    if (mDisableMessageUpdates) {
      // The screen is getting rebuilt. Don't update the info message.
      return;
    }
    SharedPreferences.Editor edit = mPreferences.edit();
    edit.putString(MESSAGE_PREFERENCE, getInfoMessage());
    edit.commit();
  }

  private String getInfoMessage() {
    final char NEWLINE = '\n';
    StringBuilder message = new StringBuilder(getResources().getString(R.string.info_message_header));
//    message.append(NEWLINE);
    message.append(NEWLINE);
    message.append(mContact.getTitle());
    for (int i = 0; i < mDisplayGroup.getPreferenceCount(); ++i) {
      Preference pref = mDisplayGroup.getPreference(i);
      if (pref instanceof CheckBoxPreference && ((CheckBoxPreference) pref).isChecked()) {
        message.append(NEWLINE);
        message.append(pref.getTitle());
      }
    }
    if (DEBUG) Log.d(TAG, "Updating info message: " + message);
    return message.toString();
  }
}
